//////////////////////// 接口初探 ////////////////////////

interface LabeledValue{
    label: string;
}

function printLabel(labeledObj: LabeledValue){
    console.log(labeledObj.label)
}
let myObj = {size:10,label:"Size 10 Object"}
printLabel(myObj)

//////////////////////// 可选属性 ////////////////////////

// option bags的例子

interface SquareConfig{
    color?: string;
    width?: number;
    // 通过字符串索引签名避免多余参数报错
    [propName:string]: any;
}

function createSquare(config: SquareConfig): {color:string;area:number}{
    let newSquare = {color: "white", area: 100}
    if(config.color){
        newSquare.color = config.color
    }
    if(config.width){
        newSquare.area = config.width * config.width
    }
    return newSquare
}

//let mySquare = createSquare({color:"black"})

// 使用类型断言绕过类型检查
//let mySquare = createSquare({colour:"black"} as SquareConfig)



//////////////////////// 只读属性 ////////////////////////

interface Point{
    readonly x: number;
    readonly y: number;
}

let p1: Point = {x: 10, y:20}

// 只读数组

let a: number[] = [1,2,3,4]
let ro: ReadonlyArray<number> = a;
// ro[0] = 12;
// ro.push(5;)
// ro.length=100;
// a=ro;

a = ro as number[]

//////////////////////// 函数类型 ////////////////////////

// 使用interface描述函数类型
interface SearchFunc{
    (source:string,subString: string): boolean;
}
// 创建一个函数类型的变量，并将一个同类型的函数赋值给这个变量
let mySearch: SearchFunc;
mySearch = function(source:string,subString:string){
    let result = source.search(subString);
    return result > -1;
}

// 函数的参数名不需要与函数接口中的名字相同
let mySearch2: SearchFunc;
mySearch2 = function(src: string,sub:string): boolean{
 let result = src.search(sub)
 return result > -1
}

// 可以不指定参数的类型
let mySearch3: SearchFunc;
mySearch3 = function(src,sub){
    let result = src.search(sub)
    return result > -1
}

//////////////////////// 可索引的类型 ////////////////////////

// 可以使用interface描述那些可以通过索引得到的类型，比如a[10]、ageMap["daniel"]
// 可索引类型具有一个“索引签名”，它描述对象索引的类型，还有相应的索引返回值类型

// 例子:
interface StringArray{
    // 索引签名，表示用number类型的值去索引StringArray时，返回string类型的值
    [index:number]: string;
}

let myArray: StringArray;
myArray = ["Bob","Fred"]

let myStr: string = myArray[0]

// typescript支持两种索引签名: 字符串和数字。
// 可以同时使用两种索引，但是数字索引的返回值必须是字符串索引返回值类型的子类型

//////////////////////// 类类型 ////////////////////////

// 实现接口
// interface ClockInterface {
//     currentTime: Date;
//     setTime(d: Date): void;
// }

// class Clock implements ClockInterface {
//     currentTime: Date = new Date()    
//     setTime(d: Date) {
//         this.currentTime = d;        
//     }
//     constructor(h: number, m: number) { }
// }

//////////// 类静态部分与实例部分的区别

// 约定构造函数的样子
interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
// 约定闹钟接口的样子
interface ClockInterface{
    tick():void;
}
// 调用不同的实现类，创建数字闹钟活模拟闹钟
function createClock(ctor: ClockConstructor,hour: number,minute:number):ClockInterface{
    return new ctor(hour, minute);
}
// 数字闹钟的实现类
class DigitalClock implements ClockInterface{
    // 需要符合ClockConstructor中描述的构造函数的样子
    constructor(h: number,m: number){}
    // 实现ClockInterface约定的函数
    tick(){
        console.log("beep beep")
    }    
}
// 模拟闹钟的实现类
class AnalogClock implements ClockInterface{
    // 需要符合ClockConstructor中描述的构造函数的样子
    constructor(h:number,m:number){}
    tick() {
        console.log("tick tock")
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);


//////////////////////// 继承接口 ////////////////////////

// interface Shape {
//     color: string;
// }

// interface Square extends Shape{
//     sideLength: number;
// }

// let square = <Square>{};
// square.color = "blue";
// square.sideLength = 10;

// 一个接口可以继承多个接口，创建出多个接口的合成接口
interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

//////////////////////// 混合类型 ////////////////////////
interface Counter{
    (start: number):string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter{
    let counter = <Counter>function(start:number){};
    counter.interval = 123;
    counter.reset = function(){};
    return counter;
}

//////////////////////// 接口继承类 ////////////////////////

class Control{
    private state: any;
}

interface SelectableControl extends Control{
    select(): void;
}

class Button extends Control implements SelectableControl{
    select(){}
}

class TextBox extends Control{
    select(){}
}

// 错误：“Image”类型缺少“state”属性。
// class Image implements SelectableControl {
//     select() { }
// }

// class Location {

// }
